package com.jianjun.ktui.util

import cn.hutool.core.io.resource.ResourceUtil
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Paths
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager

/**
 * @author source
 * `@date` 2024/9/12 09:09
 */
object UtilSsl {
    val sslSocketFactory: SSLSocketFactory
        /**
         * 忽略https证书验证
         */
        get() {
            try {
                val sslContext = SSLContext.getInstance("SSL")
                sslContext.init(null, trustManager, SecureRandom())
                return sslContext.socketFactory
            } catch (e: Exception) {
                throw RuntimeException(e)
            }
        }

    val x509TrustManager: X509TrustManager
        get() = @Suppress("CustomX509TrustManager")
        object : X509TrustManager {
            //检查客户端证书，若不信任该证书抛出异常，咱们自己就是客户端不用检查
            @Suppress("TrustAllX509TrustManager")
            override fun checkClientTrusted(
                chain: Array<X509Certificate>,
                authType: String
            ) {
            }

            //检查服务器的证书，若不信任该证书抛出异常，可以不检查默认都信任
            @Suppress("TrustAllX509TrustManager")
            override fun checkServerTrusted(
                chain: Array<X509Certificate>,
                authType: String
            ) {
            }

            //返回受信任的X509证书数组
            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        }

    private val trustManager: Array<TrustManager>
        get() =//检查客户端证书，若不信任该证书抛出异常，咱们自己就是客户端不用检查
        //检查服务器的证书，若不信任该证书抛出异常，可以不检查默认都信任
            //返回受信任的X509证书数组
            arrayOf(
                x509TrustManager
            )

    /**
     * 1：优先从 class path 与 jar 包之中获取密钥，然后从文件系统中获取密钥
     * 2：开发环境下 class path 包括 target/classes、jar 包。由于 src/main/resources
     * 目录下的资源会被 copy 到 target/classes 目录之下，因此该目录可看成是 class path
     * 3：部署环境下 class path 包括 config 目录、jar 包
     */
    @Throws(Exception::class)
    fun loadKeyStore(keyStoreType: String?, keyStore: String, keyStorePassword: String?): KeyStore {
        var stream: InputStream? = ResourceUtil.getResource(keyStore).openStream()
        if (stream == null) {
            stream = Files.newInputStream(Paths.get(keyStore))
        }
        stream.use { `is` ->
            val ret = if (keyStoreType != null) {
                //  "JKS"、"PKCS12"(.pfx)
                KeyStore.getInstance(keyStoreType)
            } else {
                // 下面代码并不能自动探测密钥库类型
                KeyStore.getInstance(KeyStore.getDefaultType())
            }
            ret.load(`is`, keyStorePassword?.trim { it <= ' ' }?.toCharArray())
            return ret
        }
    }
}
